/*
Copyright (C) 2021-2025 Casa Xu (also Zhiyan Xu) from HIT

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*
 * LOS_FLASH.c
 *
 *  Created on: 2022年
 *      Author: Casa XU
 */


#include "LOS_FLASH.h"
#include "F021.h"


 
//TMS570LC4357 FLASH分区表
struct Sector_List gSector_List[SECTOR_NUM] =
{
 //  块编号               扇区编号 扇区起始地址 扇区大小
     {Fapi_FlashBank0,    0,      0x00000000, 16*1024},
     {Fapi_FlashBank0,    1,      0x00004000, 16*1024},
     {Fapi_FlashBank0,    2,      0x00008000, 16*1024},
     {Fapi_FlashBank0,    3,      0x0000C000, 16*1024},
     {Fapi_FlashBank0,    4,      0x00010000, 16*1024},
     {Fapi_FlashBank0,    5,      0x00014000, 16*1024},
     {Fapi_FlashBank0,    6,      0x00018000, 32*1024},
     {Fapi_FlashBank0,    7,      0x00020000, 128*1024},
     {Fapi_FlashBank0,    8,      0x00040000, 128*1024},
     {Fapi_FlashBank0,    9,      0x00060000, 128*1024},
     {Fapi_FlashBank0,    10,     0x00080000, 256*1024},
     {Fapi_FlashBank0,    11,     0x000C0000, 256*1024},
     {Fapi_FlashBank0,    12,     0x00010000, 256*1024},
     {Fapi_FlashBank0,    13,     0x00014000, 256*1024},
     {Fapi_FlashBank0,    14,     0x00018000, 256*1024},
     {Fapi_FlashBank0,    15,     0x0001C000, 256*1024},
     {Fapi_FlashBank1,    0,      0x00200000, 128*1024},
     {Fapi_FlashBank1,    1,      0x00220000, 128*1024},
     {Fapi_FlashBank1,    2,      0x00240000, 128*1024},
     {Fapi_FlashBank1,    3,      0x00260000, 128*1024},
     {Fapi_FlashBank1,    4,      0x00280000, 128*1024},
     {Fapi_FlashBank1,    5,      0x002A0000, 128*1024},
     {Fapi_FlashBank1,    6,      0x002C0000, 128*1024},
     {Fapi_FlashBank1,    7,      0x002E0000, 128*1024},
     {Fapi_FlashBank1,    8,      0x00300000, 128*1024},
     {Fapi_FlashBank1,    9,      0x00320000, 128*1024},
     {Fapi_FlashBank1,    10,     0x00340000, 128*1024},
     {Fapi_FlashBank1,    11,     0x00360000, 128*1024},
     {Fapi_FlashBank1,    12,     0x00380000, 128*1024},
     {Fapi_FlashBank1,    13,     0x003A0000, 128*1024},
     {Fapi_FlashBank1,    14,     0x003C0000, 128*1024},
     {Fapi_FlashBank1,    15,     0x003E0000, 128*1024},
     {Fapi_FlashBank7,    0,      0xF0200000, 4*1024},
     {Fapi_FlashBank7,    1,      0xF0201000, 4*1024},
     {Fapi_FlashBank7,    2,      0xF0202000, 4*1024},
     {Fapi_FlashBank7,    3,      0xF0203000, 4*1024},
     {Fapi_FlashBank7,    4,      0xF0204000, 4*1024},
     {Fapi_FlashBank7,    5,      0xF0205000, 4*1024},
     {Fapi_FlashBank7,    6,      0xF0206000, 4*1024},
     {Fapi_FlashBank7,    7,      0xF0207000, 4*1024},
     {Fapi_FlashBank7,    8,      0xF0208000, 4*1024},
     {Fapi_FlashBank7,    9,      0xF0209000, 4*1024},
     {Fapi_FlashBank7,    10,     0xF020A000, 4*1024},
     {Fapi_FlashBank7,    11,     0xF020B000, 4*1024},
     {Fapi_FlashBank7,    12,     0xF020C000, 4*1024},
     {Fapi_FlashBank7,    13,     0xF020D000, 4*1024},
     {Fapi_FlashBank7,    14,     0xF020E000, 4*1024},
     {Fapi_FlashBank7,    15,     0xF020F000, 4*1024},
     {Fapi_FlashBank7,    16,     0xF0210000, 4*1024},
     {Fapi_FlashBank7,    17,     0xF0211000, 4*1024},
     {Fapi_FlashBank7,    18,     0xF0212000, 4*1024},
     {Fapi_FlashBank7,    19,     0xF0213000, 4*1024},
     {Fapi_FlashBank7,    20,     0xF0214000, 4*1024},
     {Fapi_FlashBank7,    21,     0xF0215000, 4*1024},
     {Fapi_FlashBank7,    22,     0xF0216000, 4*1024},
     {Fapi_FlashBank7,    23,     0xF0217000, 4*1024},
     {Fapi_FlashBank7,    24,     0xF0218000, 4*1024},
     {Fapi_FlashBank7,    25,     0xF0219000, 4*1024},
     {Fapi_FlashBank7,    26,     0xF021A000, 4*1024},
     {Fapi_FlashBank7,    27,     0xF021B000, 4*1024},
     {Fapi_FlashBank7,    28,     0xF021C000, 4*1024},
     {Fapi_FlashBank7,    29,     0xF021D000, 4*1024},
     {Fapi_FlashBank7,    30,     0xF021E000, 4*1024},
     {Fapi_FlashBank7,    31,     0xF021F000, 4*1024},
};
 
 
/*  @brief  查找扇区信息
*   @param[in] oNewFlashBank：块编号
*   @param[in] sector：扇区编号
*
*   return：扇区在数据结构中的位置
*/
uint32_t find_sector(Fapi_FlashBankType oNewFlashBank, uint32_t sector)
{
    int i=0;
 
    for(i=0; i<SECTOR_NUM; i++)
    {
        if( (gSector_List[i].banks_num == oNewFlashBank) && (gSector_List[i].sector_num == sector) )
        {
            return i;
        }
    }
}
 
/*  @brief  擦除扇区
*   @param[in] oNewFlashBank：块编号
*   @param[in] sector：扇区编号
*
*   return：
*/
enum e_flash_status LOS_Flash_EraseSector(Fapi_FlashBankType oNewFlashBank, uint32_t sector)
{
    int num = 0;
    Fapi_StatusType oReturnCheck = Fapi_Status_Success;
 
    num = find_sector(oNewFlashBank, sector);   //根据块ID和扇区ID查找扇区信息
 
    oReturnCheck = Fapi_initializeFlashBanks(150); //初始化Flash Bank以进行API操作,根据HALCOGEN的时钟树,hclk为150MHz
    if((oReturnCheck == Fapi_Status_Success) && (FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY != Fapi_Status_FsmBusy))
    {
       oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank);  //设置活动的Flash Bank
       if( (oNewFlashBank == Fapi_FlashBank0) || (oNewFlashBank == Fapi_FlashBank1) )
           oReturnCheck = Fapi_enableMainBankSectors( 1<<(sector) );  //设置EEPROM存储区中可用的扇区以进行擦除和编程
       else if( oNewFlashBank == Fapi_FlashBank7 )
           oReturnCheck = Fapi_enableEepromBankSectors(1<<(sector) ,1<<((sector)%32));  //设置EEPROM存储区中可用的扇区以进行擦除和编程
       while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
       Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, gSector_List[num].low_addr);  //向Flash状态机发出命令
       /* Place specific example code here */
       /* Wait for FSM to finish */
       while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
       /* Check the FSM Status to see if there were no errors */
       if (FLASH_CONTROL_REGISTER->FmStat.u32Register != 0)
       {
           /* Put Error handling code here */
           return flash_failure;
       }
    }
    return flash_succeed;
}
 
 
/*  @brief  擦除块
*   @param[in] oNewFlashBank：块编号
*
*   return：
*/
enum e_flash_status LOS_Flash_EraseBanks(Fapi_FlashBankType oNewFlashBank)
{
    int num = 0;
    Fapi_StatusType oReturnCheck = Fapi_Status_Success;
 
    num = find_sector(oNewFlashBank, 0);
 
    oReturnCheck = Fapi_initializeFlashBanks(150); //初始化Flash Bank以进行API操作
    if((oReturnCheck == Fapi_Status_Success) && (FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY != Fapi_Status_FsmBusy))
    {
       oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank);  //设置活动的Flash Bank
       if( (oNewFlashBank == Fapi_FlashBank0) || (oNewFlashBank == Fapi_FlashBank1) )
           oReturnCheck = Fapi_enableMainBankSectors( 0xffffffff );  //设置主存储区中可用的扇区以进行擦除和编程
       else if( oNewFlashBank == Fapi_FlashBank7 )
           oReturnCheck = Fapi_enableEepromBankSectors(0xffffffff, 0xffffffff);  //设置EEPROM存储区中可用的扇区以进行擦除和编程
       while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
       Fapi_issueAsyncCommandWithAddress(Fapi_EraseBank, gSector_List[num].low_addr);  //向Flash状态机发出命令
       /* Place specific example code here */
       /* Wait for FSM to finish */
       while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
       /* Check the FSM Status to see if there were no errors */
       if (FLASH_CONTROL_REGISTER->FmStat.u32Register != 0)
       {
           /* Put Error handling code here */
           return flash_failure;
       }
    }
    return flash_succeed;
}
 
/*  @brief  写扇区数据
*   @param[in] oNewFlashBank：块编号
*   @param[in] sector：扇区编号
*   @param[in] offset：扇区偏移地址
*   @param[in] buff：数据
*   @param[in] len：数据长度
*
*   return：
*/
enum e_flash_status LOS_Flash_WriteData(Fapi_FlashBankType oNewFlashBank, uint32_t sector, uint32_t offset, const uint8_t * buff, uint32_t len)
{
    int num = 0;
    uint32_t txcnt = 0;
    Fapi_StatusType oReturnCheck = Fapi_Status_Success;
 
    num = find_sector(oNewFlashBank, sector);
 
    //如果写的大小起过扇区的大小
    if( (offset+len) > gSector_List[num].size )
    {
        return flash_failure;
    }
 
    oReturnCheck = Fapi_initializeFlashBanks(150); //初始化Flash Bank以进行API操作
    if((oReturnCheck == Fapi_Status_Success) && (FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY != Fapi_Status_FsmBusy))
    {
        oReturnCheck = Fapi_setActiveFlashBank(oNewFlashBank);  //设置活动的Flash Bank
        if( (oNewFlashBank == Fapi_FlashBank0) || (oNewFlashBank == Fapi_FlashBank1) )
        {  
            oReturnCheck = Fapi_enableMainBankSectors( 0xFFFF );  //设置主存储区中可用的扇区以进行擦除和编程
        }
        else if( oNewFlashBank == Fapi_FlashBank7 )
            oReturnCheck = Fapi_enableEepromBankSectors(0xffffffff ,0xffffffff);  //设置EEPROM存储区中可用的扇区以进行擦除和编程
        while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
        if( (oNewFlashBank == Fapi_FlashBank0) || (oNewFlashBank == Fapi_FlashBank1) ) //FLASH区一次最多写32字节
        {
            if(len<=32)
            {
                Fapi_issueProgrammingCommand(gSector_List[num].low_addr+offset, buff, len, 0xf0400000+((gSector_List[num].low_addr+offset) >> 3), (len>>3), Fapi_AutoEccGeneration);  //设置数据并将程序命令发送到有效的闪存地址
                while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
            }
            else
            {
                while(len>32)
                {
                    Fapi_issueProgrammingCommand(gSector_List[num].low_addr+offset+txcnt*32, buff, 32, 0xf0400000+((gSector_List[num].low_addr+offset+txcnt*32) >> 3), (32>>3), Fapi_AutoEccGeneration);
                    while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
                    len -= 32;
                    buff += 32;
                    txcnt++;
                }
                Fapi_issueProgrammingCommand(gSector_List[num].low_addr+offset+txcnt*32, buff, len, 0xf0400000+((gSector_List[num].low_addr+offset+txcnt*32) >> 3), (len>>3), Fapi_AutoEccGeneration);
                while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
            }
        }else if( oNewFlashBank == Fapi_FlashBank7 ) //eeprom区一次最多写8字节
        {
            if(len<=8)
            {
                Fapi_issueProgrammingCommand(gSector_List[num].low_addr+offset, buff, len, 0xf0400000+((gSector_List[num].low_addr+offset) >> 3), (len>>3), Fapi_AutoEccGeneration);  //设置数据并将程序命令发送到有效的闪存地址
                while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
            }
            else
            {
                while(len>8)
                {
                    Fapi_issueProgrammingCommand(gSector_List[num].low_addr+offset+txcnt*8, buff, 8, 0xf0400000+((gSector_List[num].low_addr+offset+txcnt*8) >> 3), (8>>3), Fapi_AutoEccGeneration);
                    while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
                    len -= 8;
                    buff += 8;
                    txcnt++;
                }
                Fapi_issueProgrammingCommand(gSector_List[num].low_addr+offset+txcnt*8, buff, len, 0xf0400000+((gSector_List[num].low_addr+offset+txcnt*8) >> 3), (len>>3), Fapi_AutoEccGeneration);
                while(FLASH_CONTROL_REGISTER->FmStat.FMSTAT_BITS.BUSY == Fapi_Status_FsmBusy);
            }
        }
        /* Check the FSM Status to see if there were no errors */
        if (FLASH_CONTROL_REGISTER->FmStat.u32Register != 0)
        {
            /* Put Error handling code here */
            return flash_failure;
        }
    }
    else
    {
         return flash_failure;
    }
    return flash_succeed;
}
 
/*  @brief  读扇区数据
*   @param[in] oNewFlashBank：块编号
*   @param[in] sector：扇区编号
*   @param[in] offset：扇区偏移地址
*   @param[in] buff：数据
*   @param[in] len：数据长度
*
*   return：
*/
void LOS_Flash_ReadData(Fapi_FlashBankType oNewFlashBank, uint32_t sector, uint32_t offset, uint8_t * buff, uint32_t len)
{
    int num = 0;
 
    num = find_sector(oNewFlashBank, sector);
 
        //如果读的大小超过扇区的大小
    if( (offset+len) > gSector_List[num].size )
    {
        return flash_failure;
    }
 
    memcpy(buff, gSector_List[num].low_addr+offset, len);
}